home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_09_02 / 9n02066a < prev    next >
Text File  |  1990-12-17  |  8KB  |  287 lines

  1. /*
  2.     Find multiple copies of the same file on a single disk
  3.     drive. Compiled under Microsoft C 6.0 using:
  4.         cl /Fs /W4 /Ox /AC no_dup.c
  5.     Compiles without modifications undder TURBO C integrated
  6.     environment.
  7.     In both cases requires compact memory model libraries.
  8. */
  9.  
  10. #include "no_dup.h"
  11.  
  12. Flag first_call = True;
  13.  
  14. GlobalOpt globalopt = { False, False, 0, 0L };
  15.  
  16. int main( int argc, char **argv )
  17.     {
  18.     DirEntry *current_file, *next_file;
  19.     DirList *path, *root, *new_path;
  20.     char current_path[MAX_PATH], file_spec[MAX_FLEN];
  21.     PtrList *ptrbase, *ptrlist;
  22.     Flag duplicate = False;
  23.  
  24.     for( ; argc > 1; argc-- )
  25.         {
  26.         if(argv[argc-1][1] == 'f' || argv[argc-1][1] == 'F')
  27.             globalopt.file = True;
  28.         else if( argv[argc-1][1] == 'd'
  29.                 || argv[argc-1][1] == 'D' )
  30.             globalopt.dir  = True;
  31.         else
  32.             fprintf( stderr,
  33.                     "Invalid command line switch: %s\n",
  34.                     argv[argc-1] );
  35.         }
  36.  
  37.     strcpy( file_spec, "*.*" );
  38.     current_file = NULL;
  39.     (void) getcwd( current_path,  MAX_PATH );
  40.     fprintf( stderr, "%s\n", VERSION );
  41.     printf( "Processing %s\n", current_path );
  42.     path = make_path( current_path, "", NULL );
  43.     new_path = root = path;
  44.     if( (ptrbase = malloc( sizeof( PtrList ) * MAX_FILES ))
  45.             == NULL )
  46.         {
  47.         fprintf( stderr, "Insufficient near memory.\n" );
  48.         exit( EXIT_FAILURE );
  49.         }
  50.     ptrlist = ptrbase;
  51.  
  52.     while( (path = get_path( root ) ) != NULL )
  53.         {
  54.         strcpy( current_path, path->pathname );
  55.         strcat( current_path, file_spec );
  56.         first_call = True;
  57.  
  58.         while( (current_file = get_direntry(current_path))
  59.                 != NULL )
  60.             {
  61.             current_file->path = path->pathname;
  62.             if( current_file->attrib & FA_DIREC )
  63.                 {
  64.                 new_path = make_path( path->pathname,
  65.                         current_file->name, new_path );
  66.                 }
  67.             else
  68.                 {
  69.                 ++globalopt.file_count;
  70.                 globalopt.total_file_size
  71.                         += current_file->size;
  72.                 if( globalopt.file_count == MAX_FILES  )
  73.                     {
  74.                     fprintf( stderr,
  75.                         "Too many files\n"
  76.                         "Program is limited to %u files.\n",
  77.                         MAX_FILES );
  78.                     exit( EXIT_FAILURE );
  79.                     }
  80.                 *ptrlist = ( char * ) current_file;
  81.                 ++ptrlist;
  82.                 }
  83.             }
  84.             path->dir_processed = True;
  85.         }
  86.         *ptrlist = NULL;
  87.         printf( "Processed %d files occupying %lu bytes.\n",
  88.                 globalopt.file_count,
  89.                 globalopt.total_file_size );
  90.  
  91.         qsort( (void *) ptrbase,
  92.                 (size_t) globalopt.file_count,
  93.                 (size_t) sizeof( PtrList ), name_comp );
  94.  
  95.         if( globalopt.file )    /* optionally list files */
  96.             {
  97.             printf( SEPARATOR );
  98.             printf( "Listing of all files below %s\n",root);
  99.             for( ptrlist = ptrbase; *ptrlist; ptrlist++ )
  100.                 fprint_direntry( stdout,
  101.                         (DirEntry *) *ptrlist );
  102.             }
  103.  
  104.         printf( SEPARATOR );
  105.         printf( "Duplicate files below %s\n", root );
  106.         for( ptrlist = ptrbase, duplicate = False;
  107.                 *ptrlist; ptrlist++ )
  108.             {
  109.             current_file = ( DirEntry * ) *ptrlist;
  110.             next_file    = ( DirEntry * ) *(ptrlist+1);
  111.             if( !strcmp(current_file->name,next_file->name))
  112.                 {
  113.                 duplicate = True;
  114.                 fprint_direntry( stdout, current_file );
  115.                 }
  116.             else if( duplicate == True )
  117.                 {
  118.                 /* print the last file in a group */
  119.                 /* otherwise we'll miss it */
  120.                 current_file = ( DirEntry * ) *ptrlist;
  121.                 fprint_direntry( stdout, current_file );
  122.                 printf( SEPARATOR );
  123.                 duplicate = False;
  124.                 }
  125.             }
  126.  
  127.         return EXIT_SUCCESS;
  128.     }
  129.  
  130. /*
  131.     get file info from DOS directory and allocate memory
  132. */
  133. DirEntry *get_direntry( char *path )
  134.     {
  135.     static struct ffblk file_info;
  136.     DirEntry *new_entry;
  137.  
  138.     if( first_call == True )
  139.         {
  140.         if( findfirst( path, &file_info, FA_DIREC ) )
  141.             return NULL;
  142.         first_call = False;
  143.         }
  144.     else
  145.         {
  146.         if( findnext( &file_info ) )
  147.             {
  148.             return NULL;
  149.             }
  150.         }
  151.     if( (new_entry = malloc(sizeof(DirEntry))) == NULL )
  152.         {
  153.         fprintf( stderr, "Insufficient far memory.\n" );
  154.         exit( EXIT_FAILURE );
  155.         }
  156.  
  157.     strcpy( new_entry->name, file_info.ff_name );
  158.     new_entry->attrib = file_info.ff_attrib;
  159.     if( new_entry->attrib & FA_DIREC )
  160.         new_entry->dir_processed = False;
  161.     new_entry->time   = file_info.ff_ftime;
  162.     new_entry->date   = file_info.ff_fdate;
  163.     new_entry->size   = file_info.ff_fsize;
  164.  
  165.     return new_entry;
  166.     }
  167.  
  168. /*
  169.     build a directory path by appending subdir to basedir
  170. */
  171. DirList *make_path( char *basedir, char *subdir,
  172.         DirList *prev )
  173.     {
  174.     DirList *new_dir;
  175.  
  176.     if( (new_dir = malloc( sizeof( DirList ) ) ) == NULL )
  177.         {
  178.         fprintf( stderr, "Insufficient near memory.\n" );
  179.         exit( EXIT_FAILURE );
  180.         }
  181.     strcpy( new_dir->pathname, basedir );
  182.     strcat( new_dir->pathname, subdir );
  183.     if( *(new_dir->pathname + strlen(new_dir->pathname) - 1)
  184.             != '\\' )
  185.         strcat( new_dir->pathname, "\\" );
  186.     if( strcmp( subdir, "." ) && strcmp( subdir, ".." ) )
  187.         {
  188.         /* only "real" directories meet the condition */
  189.         new_dir->dir_processed = False;
  190.         if( globalopt.dir )
  191.             printf( "Directory:%s\n", new_dir->pathname );
  192.         }
  193.     else
  194.         new_dir->dir_processed = True;
  195.     if( prev )
  196.         {
  197.         new_dir->prev = prev;
  198.         new_dir->next = NULL;
  199.         prev->next = new_dir;
  200.         }
  201.     else
  202.         {
  203.         new_dir->prev = NULL;
  204.         new_dir->next = NULL;
  205.         }
  206.  
  207.     return new_dir;
  208.     }
  209.  
  210. /*
  211.     find an unprocessed directory
  212. */
  213. DirList *get_path( DirList *root )
  214.     {
  215.     DirList *path;
  216.  
  217.     path = root;
  218.     while( path->next && (path->dir_processed == True) )
  219.         {
  220.         path = path->next;
  221.         }
  222.     if( path->dir_processed == True)
  223.         return NULL;
  224.     else
  225.         return path;
  226.     }
  227.  
  228. /*
  229.     DirEntry comparison function
  230. */
  231. int name_comp( const void *p1, const void *p2 )
  232.     {
  233.     PtrList  *ptr1, *ptr2;
  234.     DirEntry *f1, *f2;
  235.     int status;
  236.  
  237.     ptr1 = (PtrList *) p1;
  238.     ptr2 = (PtrList *) p2;
  239.     f1   = (DirEntry *) *ptr1;
  240.     f2   = (DirEntry *) *ptr2;
  241.  
  242.     if( status = strcmp( f1->name, f2->name ) )
  243.         return( status );
  244.     else if( status = f1->date - f2->date )
  245.         return( status );
  246.     else if( status = f1->time - f2->time )
  247.         return( status );
  248.     else
  249.         return( strcmp( f1->path, f2->path  ) );
  250.     }
  251.  
  252. /*
  253.     print file information to the ouptut stream
  254. */
  255. void fprint_direntry( FILE *fout, DirEntry *current_file )
  256.     {
  257.     char date_buf[10], time_buf[10];
  258.  
  259.     fprintf( fout, "%-14s %6ld %c%c %s %s %s\n",
  260.             current_file->name,
  261.             current_file->size,
  262.             (current_file->attrib & FA_RDONLY ) ? 'R' : '.',
  263.             (current_file->attrib & FA_ARCH   ) ? 'A' : '.',
  264.             datestr( current_file->date, date_buf ),
  265.             timestr( current_file->time, time_buf ),
  266.             current_file->path );
  267.     }
  268.  
  269. /*
  270.     The following functions are copied from QC 2.0 online
  271.     help. These functions convert wr_time and wr_date into
  272.     strings.
  273. */
  274. char *timestr( unsigned t, char *buf )
  275. {
  276.     int h = (t >> 11) & 0x1f, m = (t >> 5) & 0x3f;
  277.     sprintf( buf, "%2.2d:%02.2d", h, m );